package com.zhu.tool_test.starke.matrix.multipart.core;

import com.zhu.tool_test.starke.matrix.multipart.KeyConverter;
import com.zhu.tool_test.starke.matrix.multipart.annotations.MultipartKey;
import com.zhu.tool_test.starke.matrix.multipart.wrapper.WrapMapper;
import com.zhu.tool_test.starke.util.lang.Strings;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

/**
 * @author 4everlynn
 * @version V1.0
 * @description 拼装多个PO的多部件实体
 * @date 2019/1/9
 */
public class MultipartData extends Data implements Cloneable {

    /**
     * 解析对象并放入到Map中
     *
     * @param wrapper
     * @param target  目标
     */
    private void dissect(boolean wrapper, Object target) {
        Field[] declaredFields = this.getAllDeclaredFields(target.getClass());

        Object current;
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            try {
                String key;
                if (wrapper) {
                    MultipartKey multipartKey = declaredField.getDeclaredAnnotation(MultipartKey.class);
                    if (null != multipartKey && !Strings.isNullOrEmpty(multipartKey.value())) {
                        key = multipartKey.value();
                    } else {
                        key = declaredField.getName();
                    }
                } else {
                    key = declaredField.getName();
                }
                // 获得当前值
                current = declaredField.get(target);
                this.include(key, current);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            declaredField.setAccessible(false);
        }
    }


    /**
     * 加入并合并
     * 会对@MultipartKey进行解析
     *
     * @param wrapper 指定是否解析MultipartKey
     * @param targets 目标对象
     * @return 返回自己供链式调用
     */
    public MultipartData part(boolean wrapper, Object... targets) {
        for (Object target : targets) {
            if (Map.class.isAssignableFrom(target.getClass())) {
                Map map = (Map) target;
                //noinspection unchecked
                this.putAll(map);
            } else {
                this.dissect(wrapper, target);
            }
        }
        return this;
    }

    /**
     * 加入并合并
     * 不会对@MultipartKey进行解析
     *
     * @param targets 目标对象
     * @return 返回自己供链式调用
     */
    public MultipartData parties(Object... targets) {
        return part(false, targets);
    }

    public static <T> List<MultipartData> trans2MultipartData(List<T> data) {
        List<MultipartData> multipartDataList = new ArrayList<>();
        for (T datum : data) {
            multipartDataList
                    .add(new MultipartData()
                            .parties(datum));
        }
        return multipartDataList;
    }

    public static <T> List<T> trans2Type(List<MultipartData> multipartData, Class<T> tClass) {
        List<T> tList = new ArrayList<>();
        for (MultipartData data : multipartData) {
            if (MultipartData.class.equals(tClass)) {
                //noinspection unchecked
                tList.add((T) data);
            } else {
                T t = data.get(tClass);
                tList.add(t);
            }
        }
        return tList;
    }

    @Override
    public MultipartData exclude(String key) {
        super.exclude(key);
        return this;
    }

    /**
     * 多个条件
     *
     * @param conditions 目标条件key
     * @return HASH
     */
    public Integer conditionHash(String... conditions) {
        StringBuilder builder = new StringBuilder();
        for (String key : conditions) {
            builder.append(key).append(":").append(get(key));
        }
        return builder.toString().hashCode();
    }

    /**
     * 该方法过于复杂定义不实现
     *
     * @param target 目标对象
     * @return 当前类
     */
    public MultipartData merge(MultipartData... target) {
        return this;
    }


    @Override
    public MultipartData include(String key, Object value) {
        super.include(key, value);
        return this;
    }

    @Override
    public <T> MultipartData includeIf(String key, T value, Predicate<T> predicate) {
        super.includeIf(key, value, predicate);
        return this;
    }

    /**
     * 转化所有下划线命名法 -> 驼峰命名法
     *
     * @return 当前类
     */
    public MultipartData translate2Camel() {
        MultipartData data = new MultipartData();
        KeyConverter converter = new KeyConverter();
        for (String key : this.keySet()) {
            Object o = get(key);
            String targetKey = converter.convert(key);
            data.put(targetKey, o);
        }
        return data;
    }

    public static List<MultipartData> wrapper(WrapMapper mapper, List<MultipartData> target) {
        for (MultipartData data : target) {
            data.wrapper(mapper);
        }
        return target;
    }


    @Override
    public MultipartData clone() {
        return (MultipartData) super.clone();
    }
}
